﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Singer.Shared;
using Singer.Core;
using Microsoft.AspNetCore.Mvc.Controllers;
using System.Collections.Concurrent;

namespace Singer.Framework.CoreFilters;

/// <summary>
/// WebApi 接口返回结果统一处理过滤器
/// </summary>
public class CoreApiResultFilter : IAsyncResultFilter
{
    /// <summary>
    /// Key: {Action方法全名}_{请求方式} - Value：是否忽略过滤器
    /// </summary>
    private static ConcurrentDictionary<string, bool> ActionIgnoreDic = new ConcurrentDictionary<string, bool>();
    // ConcurrentDictionary 高性能 线程安全字典：锁分段技术、CAS 操作，解决了高并发环境下锁竞争导致的性能问题。
    public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        bool ignoreFilter = CheckIgnoreFilter(context);
        if (ignoreFilter)
        {
            await next.Invoke();
            return;
        }
        if (context.Result is EmptyResult)
        {
            context.Result = new ObjectResult(CoreApiResult.Success());
        }
        if (context.Result is ObjectResult _o)
        {
            if (_o.Value is not CoreApiResult)
                context.Result = new ObjectResult(CoreApiResult.Success(_o.Value));
        }
        var objectresult = context.Result as ObjectResult;
        var cotentresult = new ContentResult()
        {
            Content = JsonUtils.ToJson(objectresult?.Value ?? ""),
            ContentType = "application/json",
            StatusCode = 200
        };
        context.Result = cotentresult;
        await next.Invoke();
    }

    /// <summary>
    /// 检查当前方法是否忽略过滤器
    /// </summary>
    private bool CheckIgnoreFilter(ResultExecutingContext context)
    {
        if (string.IsNullOrEmpty(context.ActionDescriptor.DisplayName))
            return false;
        string actionKey = $"{context.ActionDescriptor.DisplayName}_{context.HttpContext.Request.Method}";
        // 忽略过滤器： 1、指定了IgnoreFilter特性的方法； 2、所有 方法返回值是 IActionResult 或 Task<IActionResult> 的方法
        if (ActionIgnoreDic.TryGetValue(actionKey, out bool ignoreFilter))
        {
            return ignoreFilter;
        }
        else
        {
            ignoreFilter = context.ActionDescriptor.EndpointMetadata.Any(x => x is IgnoreApiResultFilterAttribute); // 包含 IgnoreFilter 特性
            if (!ignoreFilter)
            {
                if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
                {
                    var methodInfo = controllerActionDescriptor.MethodInfo;// 获取方法信息
                    var returnType = methodInfo.ReturnType;// 获取方法的返回类型
                    if (typeof(IActionResult).IsAssignableFrom(returnType))// 检查返回类型是否为 IActionResult 或其子类
                    {
                        ignoreFilter = true;
                    }
                    else
                    {
                        if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))// 处理 Task<IActionResult> 或其子类
                        {
                            var genericArguments = returnType.GetGenericArguments();
                            if (genericArguments.Length == 1 && typeof(IActionResult).IsAssignableFrom(genericArguments[0]))
                                ignoreFilter = true;
                        }
                    }
                }
            }
            ActionIgnoreDic.TryAdd(actionKey, ignoreFilter);
            return ignoreFilter;
        }
    }

}
